<!doctype html>
<html>
    <head>
        <title>列表组件手册 - HT for Web</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="user-scalable=yes, width=1024">
        <style type="text/css">
            h1, h2, h3, h4, h5, h6, p, blockquote {
                margin: 0;
                padding: 0;
            }
            body {
                font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
                font-size: 13px;
                line-height: 18px;
                color: #737373;
                background-color: white;
                margin: 10px 13px 10px 13px;
            }
            table {
                margin: 10px 0 15px 0;
                border-collapse: collapse;
            }
            td,th {
                border: 1px solid #ddd;
                padding: 3px 10px;
            }
            th {
                padding: 5px 10px;
            }
            a {
                color: #0069d6;
            }
            a:hover {
                color: #0050a3;
                text-decoration: none;
            }
            a img {
                border: none;
            }
            p {
                margin-bottom: 9px;
            }
            h1, h2, h3, h4, h5, h6 {
                color: #404040;
                line-height: 36px;
            }
            h1 {
                margin-bottom: 18px;
                font-size: 30px;
            }
            h2 {
                font-size: 24px;
            }
            h3 {
                font-size: 18px;
            }
            h4 {
                font-size: 16px;
            }
            h5 {
                font-size: 14px;
            }
            h6 {
                font-size: 13px;
            }
            hr {
                margin: 0 0 19px;
                border: 0;
                border-bottom: 1px solid #ccc;
            }
            blockquote {
                padding: 13px 13px 21px 15px;
                margin-bottom: 18px;
                font-family:georgia,serif;
                font-style: italic;
            }
            blockquote:before {
                content:"\201C";
                font-size:40px;
                margin-left:-10px;
                font-family:georgia,serif;
                color:#eee;
            }
            blockquote p {
                font-size: 14px;
                font-weight: 300;
                line-height: 18px;
                margin-bottom: 0;
                font-style: italic;
            }
            code, pre {
                font-family: Monaco, Andale Mono, Courier New, monospace;
            }
            code {
                background-color: #fee9cc;
                color: rgba(0, 0, 0, 0.75);
                padding: 1px 3px;
                font-size: 12px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
                border-radius: 3px;
            }
            pre {
                display: block;
                padding: 14px;
                margin: 0 0 18px;
                line-height: 16px;
                font-size: 11px;
                border: 1px solid #d9d9d9;
                white-space: pre-wrap;
                word-wrap: break-word;
            }
            pre code {
                background-color: #fff;
                color:#737373;
                font-size: 11px;
                padding: 0;
            }
            sup {
                font-size: 0.83em;
                vertical-align: super;
                line-height: 0;
            }
            * {
                -webkit-print-color-adjust: exact;
            }
            @media screen and (min-width: 914px) {
                body {
                    width: 854px;
                    margin:10px auto;
                }
            }
            @media print {
                body,code,pre code,h1,h2,h3,h4,h5,h6 {
                    color: black;
                }
                table, pre {
                    page-break-inside: avoid;
                }
            }
            iframe{
                width: 100%;
                border: 1px solid #34495E;
                margin: 0;
            }
            .logo{
                vertical-align: middle;
            }

        </style>
        <script>
            function init() {
                var logoSrc = '',
                    logos = document.querySelectorAll('.logo'),
                    i = 0;
                for (; i < logos.length; i++) {
                    logos[i].src = logoSrc;
                }

                var iframes = document.querySelectorAll('iframe'),
                    func = function(){};
                for (i=0; i < iframes.length; i++) {
                    var iframe = iframes[i];

                    // a small hack to make it work on android
                    iframe.ontouchstart = func;

                    if (window.location && window.location.hostname && window.location.hostname.indexOf('hightopo') >= 0) {
                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '<a href="https://hightopo.com/codeeditor/index.html?url=' + iframe.contentWindow.location.pathname + '" target="_blank">在线编辑</a>';
                        iframe.parentNode.insertBefore(div, iframe);

                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;';
                        iframe.parentNode.insertBefore(div, iframe);
                    }

                    var div = document.createElement('div');
                    div.innerHTML = '<a href="' + iframe.src + '" target="_blank">独立运行→</a>';
                    iframe.parentNode.insertBefore(div, iframe);
                }
            }
        </script>
    </head>
    <body onload="init();">
        <a href="http://www.hightopo.com"><img class="logo"></a>HT for Web 列表组件手册
        <hr style="margin: 1px 0 20px 0">
<p>索引</p>

<ul><li><a href="#ref_overview">概述</a></li><li><a href="#ref_listview">列表组件</a></li></ul>

<hr/>

<div id="ref_overview"></div>

<h2>概述</h2>

<p><code>HT for Web</code>提供了列表组件类<code>ht.widget.ListView</code>，用于显示<code>DataModel</code>数据容器中<code>Data</code>类型对象的属性信息，支持排序和过滤等功能。</p>

<p>通过<code>listView = new ht.widget.ListView(dataModel);</code>初始化构建一个列表组件对象，<code>dataModel</code>参数为列表组件绑定的数据模型，
该模型为空时列表组件构造函数内部将创建一个新的数据模型进行绑定。</p>

<div id="ref_listview"></div>

<h2>列表组件</h2>

<p>列表组件类<code>ht.widget.ListView</code>主要可配置属性和函数如下：</p>

<ul><li><code>enableToolTip()</code>和<code>disableToolTip()</code>开启和关闭文字提示</li><li><code>isDisabled()</code>和<code>setDisabled(true/false, iconURL)</code>可获取和设置整个组件处于不可用状态</li><li><code>addTopPainter(func)</code>和<code>removeTopPainter(func)</code>增加和删除顶层绘制器<code>function(g){...}</code></li><li><code>addBottomPainter(func)</code>和<code>removeBottomPainter(func)</code>增加和删除底层绘制器<code>function(g){...}</code></li><li><code>getRowHeight()</code>和<code>setRowHeight(20)</code>获取和设置行高</li><li><code>isRowLineVisible()</code>和<code>setRowLineVisible(true/false)</code>获取和设置行线是否可见，默认为<code>true</code></li><li><code>getRowLineColor()</code>和<code>setRowLineColor(color)</code>获取和设置行线颜色</li><li><code>getSortFunc()</code>和<code>setSortFunc(sortFunc)</code>获取和设置排序函数</li><li><code>getVisibleFunc()</code>和<code>setVisibleFunc()</code>获取和设置可见过滤器，其可过滤<code>DataModel</code>中的<code>Data</code>数据对象</li><li><code>getScrollBarColor()</code>和<code>setScrollBarColor(color)</code>获取和设置滚动条颜色</li><li><code>getScrollBarSize()</code>和<code>setScrollBarSize(6)</code>获取和设置滚动条宽度</li><li><code>isAutoHideScrollBar()</code>和<code>setAutoHideScrollBar(true/false)</code>获取和设置是否自动隐藏滚动条，默认为<code>true</code></li><li><code>isCheckModel()</code>和<code>setCheckMode(true/false)</code>获取和设置是否为<code>check</code>模式，默认为<code>false</code></li><li><code>getCheckIcon(data)</code>返回<code>data</code>对象对应的<code>check</code>图标，可重载自定义<code>check</code>图标，该函数在<code>checkMode</code>模式下有效</li><li><code>getFocusData()</code>、<code>setFocusData(data)</code>和<code>setFocusDataById(id)</code>在<code>checkMode</code>模式下图元除了被选中有<code>check</code>状态外，还可以有被点击行的<code>focus</code>状态</li><li><code>drawRow(g, data, selected, x, y, width, height)</code>绘制行，可重载自定义行渲染。</li><li><code>getDataAt(pointOrEvent)</code>传入逻辑坐标点或交互事件<code>event</code>参数，返回对应的<code>data</code>对象或空</li><li><code>getToolTip(event)</code>根据传入的交互事件，返回文本提示信息，可重载自定义</li><li><code>onDataDoubleClicked(data, event)</code>当<code>data</code>所在行被双击时回调，可重载对双击事件做响应          </li><li><code>onDataClicked(data, event)</code>当<code>data</code>所在行被单击时回调，可重载对单击事件做响应 </li><li><code>getLabel(data)</code>返回<code>data</code>对象显示的文字，默认返回<code>data.toLabel()</code>，可重载自定义</li><li><code>getIcon(data)</code>返回<code>data</code>对象对应的<code>icon</code>图标，可重载自定义                    </li><li><code>getLabelFont(data)</code>返回对应的单元格文本字体，可重载自定义</li><li><code>getLabelColor(data)</code>返回对应的单元格文本颜色，可重载自定义</li><li><code>getSelectBackground(data)</code>和<code>setSelectBackground(color)</code>获取和设置行选中背景颜色</li><li><code>getStartRowIndex()</code>返回当前可见区域的起始行索引</li><li><code>getEndRowIndex()</code>返回当前可见区域的结束行索引</li><li><code>getRowDatas()</code>返回当前显示的<code>Data</code>对象数组，该数组已被排序和过滤</li><li><code>getRowIndex(data)</code>返回<code>data</code>对象所在的行索引</li><li><code>getRowSize()</code>返回当前可见行总行数</li><li><code>isVisible(data)</code>判断<code>data</code>对象是否可见，可重载自定义</li><li><code>getDataModel()</code>获取绑定的<code>DatModel</code>数据模型</li><li><code>setDataModel(dataModel)</code>绑定新的<code>DatModel</code>数据模型</li><li><code>makeVisible(data)</code>该函数触发组件滚动到确保<code>data</code>对象出现在可见区域。</li><li><code>invalidateModel()</code>该函数触发组件重新排序过滤加载数据，一般组件会自动调用，除非数据变化但未派发事件时才需强制调用</li><li><code>redraw()</code>重绘刷新，注意该函数不会触发数据模型的重新加载</li><li><code>invalidateData(data)</code>调用该函数会重绘<code>data</code>对象所在行</li><li><code>drawRow(g, data, selected, x, y, width, height)</code>绘制行内容，可重载自定义</li><li><code>drawRowBackground(g, data, selected, x, y, width, height)</code>绘制行背景色，默认仅在选中该行时填充选中背景色，可重载自定义</li><li><code>drawLabel(g, data, x, y, height)</code>绘制文本，可重载自定义，<code>label</code>一般绘制在最后因此没有<code>width</code>参数限制</li><li><code>drawIcon(g, data, x, y, width, height)</code>绘制图标，可重载自定义，这里<code>width</code>值取值于<code>getIconWidth</code>函数</li><li><code>getIconWidth(data)</code>返回<code>data</code>对象对应的图标宽度，默认如果有图标则以<code>indent</code>值为宽度，可重载自定义</li><li><code>getIndent()</code>和<code>setIndent(20)</code>获取和设置<code>indent</code>缩进，该参数一般用于指定图标的宽度</li><li><code>handleDragAndDrop(event, state)</code>该函数默认为空，若该函数被重载，则<code>pan</code>平移组件功能将被关闭<ul><li><code>event</code>鼠标或<code>Touch</code>交互事件</li><li><code>state</code>当前状态，先后会有<code>prepare</code>-<code>begin</code>-<code>between</code>-<code>end</code>四种过程</li></ul></li></ul>

<p><iframe src="examples/example_custom.html" style="height:300px"></iframe></p>

<p>以下代码重载了drawRowBackground函数，绘制了列表行交替斑马线的效果：</p>

<pre><code>listView.drawRowBackground = function(g, data, selected, x, y, width, height){
    if(this.isSelected(data)){
        g.fillStyle = &#39;#87A6CB&#39;;
    }
    else if(this.getRowIndex(data) % 2 === 0){
        g.fillStyle = &#39;#F1F4F7&#39;;
    }
    else{
        g.fillStyle = &#39;#FAFAFA&#39;;
    }
    g.beginPath();
    g.rect(x, y, width, height);
    g.fill();
};</code></pre>

<p>自定义了<code>productIcon</code>矢量图标，该图标设置了clip函数将图片裁剪成圆形效果，设置了<code>listView.setIndent(60)</code>为图片留出缩进间距，
重载了<code>listView.getIcon</code>函数，所有<code>data</code>都返回<code>productIcon</code>的矢量图标：</p>

<pre><code>ht.Default.setImage(&#39;productIcon&#39;, {
    width: 50,
    height: 50,
    clip: function(g, width, height) {   
        g.beginPath();
        g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true);
        g.clip();                        
    },
    comps: [
        {
            type: &#39;image&#39;,
            stretch: &#39;uniform&#39;,
            rect: [0, 0, 50, 50],
            name: {func: function(data){return &#39;images/&#39; + data.a(&#39;ProductId&#39;) + &#39;.jpg&#39;;}}
        }
    ]
});
listView.setIndent(60);                 
listView.getIcon = function(data){
    return &#39;productIcon&#39;;
}; </code></pre>

<p>自定义了<code>getLabel</code>根据<code>attr</code>定义的属性组合成<code>label</code>信息，自定义了<code>getToolTip</code>函数，以<code>html</code>格式返回文本提示信息：</p>

<pre><code>listView.enableToolTip();
listView.getLabel = function(data){
    return data.a(&#39;ProductName&#39;) + &#39; - $&#39; + data.a(&#39;UnitPrice&#39;).toFixed(2);
};                
listView.getToolTip = function(e){
    var data = this.getDataAt(e);
    if(data){
        return &#39;&lt;span style=&quot;color:#3D97D0&quot;&gt;ProductId:&amp;nbsp;&lt;/span&gt;&#39; + data.a(&#39;ProductId&#39;) + &#39;&lt;br&gt;&#39; +  
               &#39;&lt;span style=&quot;color:#3D97D0&quot;&gt;ProductName:&amp;nbsp;&lt;/span&gt;&#39; + data.a(&#39;ProductName&#39;) + &#39;&lt;br&gt;&#39; +  
               &#39;&lt;span style=&quot;color:#3D97D0&quot;&gt;QuantityPerUnit:&amp;nbsp;&lt;/span&gt;&#39; + data.a(&#39;QuantityPerUnit&#39;) + &#39;&lt;br&gt;&#39; + 
               &#39;&lt;span style=&quot;color:#3D97D0&quot;&gt;Description:&amp;nbsp;&lt;/span&gt;&#39; + data.a(&#39;Description&#39;);                        
    }
    return null;
};</code></pre>

<p>通过<code>listView.setSortFunc</code>设置了排序函数，根据<code>attr</code>上的<code>UnitPrice</code>价格属性进行对比：</p>

<pre><code>sortFunc = function(d1, d2){
    return d1.a(&#39;UnitPrice&#39;) - d2.a(&#39;UnitPrice&#39;);
};
listView.setSortFunc(sortFunc);

toolbar.setItems([                    
    {
        label: &#39;Sort by price&#39;,
        type: &#39;toggle&#39;,
        selected: true,
        action: function(){
            listView.setSortFunc(this.selected ? sortFunc : null);
        }
    }
]); </code></pre>

<p>通过<code>listView.setVisibleFunc</code>设置了行过滤器，根据<code>toolbar</code>上的文本输入框内容进行过滤：</p>

<pre><code>toolbar.setItems([                    
    {
        id: &#39;text&#39;,
        label: &#39;Search&#39;,
        icon: &#39;images/search.png&#39;,
        textField: {
            width: 120
        }
    }
]);
toolbar.getItemById(&#39;text&#39;).element.getElement().onkeyup = function(e){
    listView.invalidateModel();
};
listView.setVisibleFunc(function(data){                    
    var text = toolbar.v(&#39;text&#39;);
    if(text){                        
        return data.a(&#39;ProductName&#39;).toLowerCase().indexOf(text.toLowerCase()) &gt;= 0;
    }
    return true;
}); </code></pre>    <hr id="contact" style="margin: 20px 0 1px 0">
    <a href="http://www.hightopo.com"><img class="logo"></a>欢迎交流 <a href="mailto:service@hightopo.com">service@hightopo.com</a>
</body>
</html>
